/*
 * MovementHandler.cpp
 *
 *  Created on: 28/10/2013
 *      Author: fernando
 */

#include "MovementHandler.h"
#include "Confite.h"
#include "Barrita.h"
#include "EstrellaDorada.h"
#include "jsoncpp/json/json.h"
#include "../../Common/mensaje.h"
#include <math.h>
#include <cstdlib>
#include <vector>
#include <openssl/hmac.h>
#include <sstream>
#include <string>
#include "Jugada.h"

using std::vector;
using std::abs;
using std::string;

const int MAXMOV = 64;
const int HORIZONTAL = 0;
const int VERTICAL = 1;
extern const int SIZEEXTRA;
extern const int SIZECELDA;
const int TAMCELL = 64;
const int FRAMES = 10;

int getDiferencia(int a, int b){
	return (a-b);
}

MovementHandler::MovementHandler(TableroSDL* tableroAUsar, Conexion* sock,std::string k) {
	limiteAlcanzado = false;
	mouseApretado = false;
	xOrigen = 0;
	yOrigen = 0;
	xActual = 0;
	yActual = 0;
	tablero = tableroAUsar;
	direccion = -1;
	stream = sock;
	terminar = false;
	bloqueado = false;
	gano = false;
	key = k;
}

MovementHandler::~MovementHandler(){
}

void MovementHandler::ubicarMouse(unsigned int x, unsigned int y){
	int diferenciaX, diferenciaY;
	if(!limiteAlcanzado && x > 0 && y > 0 &&
			x < tablero->getAncho()-SIZEEXTRA){
		xActual = x;
		yActual = y;
	}
	if (mouseApretado){
		diferenciaX = abs(getDiferencia(x,xOrigen));
		diferenciaY = abs(getDiferencia(y,yOrigen));
		if (direccion == -1){
			if (diferenciaX > diferenciaY){
				direccion = 0;
			}else{
				direccion = 1;
			}
		}
		if((diferenciaX >= MAXMOV) || (diferenciaY >= MAXMOV)){
			limiteAlcanzado = true;
		}
		moverGolosina();
	}
}

void MovementHandler::moverGolosina(){
	if (direccion == 0){
		golosinaOrigen->setPosicion(tablero->getPosCorner(xActual),
				tablero->getPosCorner(yOrigen));
	}else{
		golosinaOrigen->setPosicion(tablero->getPosCorner(xOrigen),
				tablero->getPosCorner(yActual));
	}
	golosinaOrigen->dibujar(tablero->getScreen(), false);
}

void MovementHandler::pulsaGolosina(){
	xOrigen = xActual;
	yOrigen = yActual;
	if (!mouseApretado){
		golosinaOrigen = tablero->getGolosinaConPosicion(xActual, yActual);
		if (golosinaOrigen != NULL){
			mouseApretado = true;
		}
	}
}

int MovementHandler::soltarGolosina(){
	CeldaSDL *celdaOrigen, *celdaDestino;
	int puntaje = 0;
	if (mouseApretado){
		celdaDestino = tablero->getCeldaFromPos(golosinaOrigen->getPosX(),
				golosinaOrigen->getPosY());
		celdaOrigen = tablero->getCeldaFromPos(xOrigen, yOrigen);
		if (celdaDestino->getEstado() && !celdaDestino->isVacia()
				&& !(*celdaDestino == *celdaOrigen)){
			golosinaDestino = celdaDestino->getGolosina();
			golosinaDestino->setPosicion(celdaOrigen->getPosX(),
					celdaOrigen->getPosY());
			celdaOrigen->setGolosina(golosinaDestino);
			golosinaOrigen->setPosicion(celdaDestino->getPosX(),
					celdaDestino->getPosY());
			celdaDestino->setGolosina(golosinaOrigen);
			enviarIntercambio(celdaOrigen->getNumero(),
					celdaDestino->getNumero());
		}else{
			golosinaOrigen->setPosicion(celdaOrigen->getPosX(),
					celdaOrigen->getPosY());
		}
		mouseApretado = false;
		limiteAlcanzado = false;
		direccion = -1;
		golosinaOrigen = NULL;
		golosinaDestino = NULL;
	}
	return puntaje;
}

//void MovementHandler::destruirGolosina(CeldaSDL* celda){
//	Mix_PlayChannel(-1, explode, 0);
//	celda->destruirContenido();
//	if (((celda->getNumero())%(tablero->getNumeroFilas())) > 0){
//		bajarGolosina(celda->getNumero() - 1);
//	}
//}


void MovementHandler::intercambiar(unsigned int celda1, unsigned int celda2){
	CeldaSDL* celdaOrigen = tablero->getCelda(celda1);
	CeldaSDL* celdaDestino = tablero->getCelda(celda2);
	Golosina* golosinaDestino = celdaDestino->getGolosina();
	Golosina* golosinaOrigen = celdaOrigen->getGolosina();
	golosinaDestino->setPosicion(celdaOrigen->getPosX(),
									celdaOrigen->getPosY());
	celdaOrigen->setGolosina(golosinaDestino);
	golosinaOrigen->setPosicion(celdaDestino->getPosX(),
									celdaDestino->getPosY());
	celdaDestino->setGolosina(golosinaOrigen);
}

void MovementHandler::eliminarYRellenarPosiciones(Json::Value jugada){
//	CeldaSDL* celdaVista;
	Golosina * gol;
	int color;
	int orientacion;
	unsigned int nroFila;
	unsigned int nroCol;
	unsigned int posX;
	unsigned int posY;
	Jugada* jugadaActual = new Jugada();
	//Relleno con las especiales
	for (Json::Value::iterator it = jugada["especiales"].begin();
			it != jugada["especiales"].end(); ++it) {
		int nCel = (*it)["numCelda"].asInt();
		jugadaActual->addPosEspecial(nCel);
//		celdaVista = tablero->getCelda(nCel);
//		celdaVista->destruirContenido();
		std::string pieza = (*it)["pieza"].get("tipo","null").asString();
		nroFila = nCel%tablero->getNumeroFilas();
		nroCol = nCel/tablero->getNumeroFilas();
		posX = nroCol*TAMCELL;
		posY = nroFila*TAMCELL;
		if (pieza == "minibar"){
			color = (*it)["pieza"].get("color",0).asInt();
			orientacion = (*it)["pieza"].get("orientacion",0).asInt();
			gol = new Barrita(color,orientacion,posX,posY);
		} else if (pieza == "GoldenStar"){
			gol = new EstrellaDorada(posX,posY);
		} else {
			color = (*it)["pieza"].get("color",0).asInt();
			gol = new Confite(color,posX,posY);
		}
		jugadaActual->addReemplazoEsp(gol);
//		celdaVista->setGolosina(gol);
	}
	//Relleno con las comunes
	for (Json::Value::iterator it = jugada["piezas"].begin();
			it != jugada["piezas"].end(); ++it) {
		int nCel = (*it)["numCelda"].asInt();
//		celdaVista = tablero->getCelda(nCel);
//		destruirGolosina(celdaVista);
		std::string pieza = (*it)["pieza"].get("tipo","null").asString();
		nroFila = nCel%tablero->getNumeroFilas();
		nroCol = nCel/tablero->getNumeroFilas();
		jugadaActual->addPosComun(nCel);
		posX = nroCol*TAMCELL;
		posY = nroFila*TAMCELL;
		if (pieza == "minibar"){
			  color = (*it)["pieza"].get("color",0).asInt();
			  orientacion = (*it)["pieza"].get("orientacion",0).asInt();
			  gol = new Barrita(color,orientacion,posX,posY);
		} else if (pieza == "GoldenStar"){
			  gol = new EstrellaDorada(posX,posY);
		} else {
			color = (*it)["pieza"].get("color",0).asInt();
			  gol = new Confite(color,posX,posY);
		}
		jugadaActual->addReemplazoComun(gol);
//		reponerGolosina(gol, nroCol);
	}
	tablero->addJugada(jugadaActual);
	//	SDL_Delay(200);
}


void MovementHandler::enviarIntercambio(unsigned int numCelOrigen,
		unsigned int numCelDestino){
	Json::Value mensajeJSon;
	string mensaje = "";
	// La key para el hasheo
	//const char vkey[] = key.c_str();
//	unsigned char* origHasheado;
	HMAC_CTX ctx;
	HMAC_CTX_init(&ctx);
	//longitud que necesita el sha1
	unsigned int len = 20;

	//string key = "012345678";
	Mensaje msj;
	Json::Value res;
//	mensajeJSon["flag"] = "m";
	mensajeJSon["c1"] = numCelOrigen;
	mensajeJSon["c2"] = numCelDestino;
	Json::Value msjJsonFinal(Json::objectValue);
	msjJsonFinal["original"] = mensajeJSon;
	unsigned char* menHasheado;
	menHasheado = (unsigned char*)malloc(sizeof(char) * len);

	// Se usa sha1 como motor de hasheo
	HMAC_Init_ex(&ctx, key.c_str(), strlen(key.c_str()), EVP_sha1(), NULL);
	HMAC_Update(&ctx, (unsigned char*)msjJsonFinal["original"].toStyledString().c_str(),
			strlen(msjJsonFinal["original"].toStyledString().c_str()));
	HMAC_Final(&ctx, menHasheado, &len);
	HMAC_CTX_cleanup(&ctx);

	std::stringstream ss;
	ss << menHasheado;
	std::string menHashFinal = ss.str();

	// Se hashea el mensaje enviado, usando el motor sha1
	//menHasheado = HMAC(EVP_sha1(), key.c_str(), strlen(key.c_str()), (unsigned char*)mensajeJSon.toStyledString().c_str(), strlen(mensajeJSon.toStyledString().c_str()), NULL, NULL);
	msjJsonFinal["hasheado"] = menHashFinal;//menHashFinal;
	msjJsonFinal["flag"] = "m";
	mensaje = msjJsonFinal.toStyledString();
	stream->send(mensaje);
	free(menHasheado);
}

TableroSDL* MovementHandler::getTablero(){
	return tablero;
}

Conexion* MovementHandler::getStream(){
	return stream;
}

void MovementHandler::setJsonMov(Json::Value movs){
	resMovimiento = movs;
}

bool MovementHandler::getTerminar(){
	return terminar;
}

void MovementHandler::setTerminar(bool value){
	terminar = value;
}

void MovementHandler::setBloqueo(bool value){
	bloqueado = value;
}

bool MovementHandler::getBloqueo(){
	return bloqueado;
}

bool MovementHandler::getGano(){
	return gano;
}

void MovementHandler::setGano(bool value){
	gano = value;
}

